package com.nd.fastdp.workflow.service;

import com.nd.fastdp.workflow.constant.*;
import com.nd.fastdp.workflow.convert.UndoConvert;
import com.nd.fastdp.workflow.dao.UndoMapper;
import com.nd.fastdp.workflow.model.bo.procdef.ProcdefBO;
import com.nd.fastdp.workflow.model.bo.procinst.ProcinstBO;
import com.nd.fastdp.workflow.model.bo.task.TaskBO;
import com.nd.fastdp.workflow.model.bo.undo.UndoBO;
import com.nd.fastdp.workflow.model.dto.task.TaskAddParam;
import com.nd.fastdp.workflow.model.dto.undo.*;
import com.nd.fastdp.workflow.model.entity.Undo;
import com.nd.fastdp.workflow.model.pojo.Node;
import com.nd.fastdp.workflow.serivce.ProcdefService;
import com.nd.fastdp.workflow.serivce.ProcinstService;
import com.nd.fastdp.workflow.serivce.TaskService;
import com.nd.fastdp.workflow.serivce.UndoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;

@Service
public class UndoServiceImpl implements UndoService {

    @Autowired
    private ProcdefService procdefService;

    @Autowired
    private UndoMapper undoMapper;

    @Autowired
    private TaskService taskService;

    @Autowired
    private ProcinstService procinstService;

    @Autowired
    private Map<String, WorkFlowListener> workFlowListenerMap;

    @Override
    public UndoBO get(String id) {

        Undo undo = undoMapper.selectById(id);

        return  UndoConvert.INSTANCE.to(undo);
    }

    @Override
    public void add(UndoAddParam param) {

        Undo undo = UndoConvert.INSTANCE.from(param);

        undo.setCreateTime(System.currentTimeMillis());
        undo.setFinished(UndoFinishedFlagEnum.PROCESSING.getValue());
        undo.setResult(UndoResultEnum.WAIT_HANDLE.getValue());

        undoMapper.insert(undo);

        //回调等待处理业务
        Undo targetUndo = undoMapper.selectById(undo.getId());
        ProcinstBO procinstBO = procinstService.get(targetUndo.getProcinstId());
        ProcdefBO procdefBO = procdefService.get(procinstBO.getProcdefId());
        TaskBO taskBO = taskService.get(targetUndo.getTaskId());
        WorkFlowListener workFlowListener = workFlowListenerMap.get("workFlowListener_" + procdefBO.getCode());
        if(workFlowListener == null){
            workFlowListener = workFlowListenerMap.get("defaultWorkFlowListener");
        }

        workFlowListener.waitHandler(procinstBO, taskBO, get(undo.getId()));
    }

    /**
     * 已读
     */
    @Override
    public void read(UndoReadParam param) {

        Undo undo = new Undo();
        undo.setId(param.getUndoId());

        undo.setSuggest(param.getSuggest());
        undo.setResult(UndoResultEnum.READED.getValue());
        undo.setFinished(UndoFinishedFlagEnum.PROCESSEND.getValue());
        undo.setAssertionTime(System.currentTimeMillis());

        undoMapper.updateById(undo);

        taskService.addReadCount(undoMapper.selectById(param.getUndoId()).getTaskId());

        //回调已读处理业务
        Undo targetUndo = undoMapper.selectById(param.getUndoId());
        ProcinstBO procinstBO = procinstService.get(targetUndo.getProcinstId());
        ProcdefBO procdefBO = procdefService.get(procinstBO.getProcdefId());
        TaskBO taskBO = taskService.get(targetUndo.getTaskId());
        WorkFlowListener workFlowListener = workFlowListenerMap.get("workFlowListener_" + procdefBO.getCode());
        if(workFlowListener == null){
            workFlowListener = workFlowListenerMap.get("defaultWorkFlowListener");
        }

        workFlowListener.read(procinstBO, taskBO, get(param.getUndoId()));
    }

    /**
     * 委托
     * @param param
     */
    @Override
    @Transactional
    public void assignor(UndoAssignorParam param) {

        Undo undo = new Undo();

        undo.setId(param.getUndoId());
        undo.setSuggest(param.getSuggest());
        undo.setResult(UndoResultEnum.ASSIGNOR.getValue());
        undo.setFinished(UndoFinishedFlagEnum.PROCESSEND.getValue());
        undo.setAssertionTime(System.currentTimeMillis());

        undoMapper.updateById(undo);


        Undo beforeUndo = undoMapper.selectById(param.getUndoId());


        Undo assignorUndo = new Undo();

        assignorUndo.setTaskId(beforeUndo.getTaskId());
        assignorUndo.setProcinstId(beforeUndo.getProcinstId());
        assignorUndo.setResult(UndoResultEnum.WAIT_HANDLE.getValue());
        assignorUndo.setFinished(UndoFinishedFlagEnum.PROCESSING.getValue());
        assignorUndo.setAssignorUndoId(beforeUndo.getId());
        assignorUndo.setUserId(param.getUserId());
        assignorUndo.setUserName(param.getUserName());
        assignorUndo.setDeptId(param.getDeptId());
        assignorUndo.setDeptName(param.getDeptId());
        assignorUndo.setCreateTime(System.currentTimeMillis());

        undoMapper.insert(assignorUndo);

        //回调委托处理业务
        Undo targetUndo = undoMapper.selectById(param.getUndoId());
        ProcinstBO procinstBO = procinstService.get(targetUndo.getProcinstId());
        ProcdefBO procdefBO = procdefService.get(procinstBO.getProcdefId());
        TaskBO taskBO = taskService.get(targetUndo.getTaskId());
        WorkFlowListener workFlowListener = workFlowListenerMap.get("workFlowListener_" + procdefBO.getCode());
        if(workFlowListener == null){
            workFlowListener = workFlowListenerMap.get("defaultWorkFlowListener");
        }

        workFlowListener.assignor(procinstBO, taskBO, get(param.getUndoId()), get(assignorUndo.getId()));
    }

    /**
     * 同意
     * @param param
     */
    @Override
    @Transactional
    public void agree(UndoAgreeParam param) {

        Undo targetUndo = undoMapper.selectById(param.getUndoId());

        Undo undo = new Undo();
        undo.setId(param.getUndoId());

        undo.setSuggest(param.getSuggest());
        undo.setResult(UndoResultEnum.AGREE.getValue());
        undo.setFinished(UndoFinishedFlagEnum.PROCESSEND.getValue());
        undo.setAssertionTime(System.currentTimeMillis());

        undoMapper.updateById(undo);

        //增加同意处理数,返回剩余未处理数
        Integer unCompleteNum =  taskService.addAgreenCount(targetUndo.getTaskId());

        if(unCompleteNum <= 0){

            taskService.finished(targetUndo.getTaskId(), TaskStateFlagEnum.PASS.getValue());

            ProcinstBO procinstBO = procinstService.get(targetUndo.getProcinstId());

            List<Node> nodeList = Node.parseList(procinstBO.getNodeList());

            if(procinstBO.getStep() >= nodeList.size()){

                procinstService.finished(procinstBO.getId(), ProcinstStateType.PASS.getValue());

            }else{

                Boolean hasNext = false;
                for (int i = procinstBO.getStep() + 1; i < nodeList.size(); i++){

                    procinstService.addStep(procinstBO.getId());

                    if(nodeList.get(i).getProperties().getMenbers() == null && nodeList.get(i).getProperties().getMenbers().size() <= 0){

                        continue;
                    }

                    //添加任务
                    TaskAddParam taskAddParam = new TaskAddParam();
                    taskAddParam.setProcinstId(procinstBO.getId());
                    taskAddParam.setNode(nodeList.get(i));

                    TaskBO taskBO = taskService.add(taskAddParam);

                    if(NodeTypes.APPROVER.getValue().equals(nodeList.get(i).getType())){//抄送任务自动结束直接转发到第一个审批节点中

                        hasNext = true;

                        break;
                    }
                }

                //只有抄送没有审批
                if(!hasNext){
                    procinstService.finished(procinstBO.getId(), ProcinstStateType.PASS.getValue());
                }
            }
        }

        //回调同意处理业务
        ProcinstBO procinstBO = procinstService.get(targetUndo.getProcinstId());
        ProcdefBO procdefBO = procdefService.get(procinstBO.getProcdefId());
        TaskBO taskBO = taskService.get(targetUndo.getTaskId());
        WorkFlowListener workFlowListener = workFlowListenerMap.get("workFlowListener_" + procdefBO.getCode());
        if(workFlowListener == null){
            workFlowListener = workFlowListenerMap.get("defaultWorkFlowListener");
        }

        workFlowListener.agree(procinstBO, taskBO, get(param.getUndoId()));
    }

    /**
     * 拒绝
     * @param param
     */
    @Override
    @Transactional
    public void refuse(UndoRefuseParam param) {

        Undo targetUndo = undoMapper.selectById(param.getUndoId());

        Undo undo = new Undo();
        undo.setId(param.getUndoId());

        undo.setSuggest(param.getSuggest());
        undo.setResult(UndoResultEnum.REFUSE.getValue());
        undo.setFinished(UndoFinishedFlagEnum.PROCESSEND.getValue());
        undo.setAssertionTime(System.currentTimeMillis());

        undoMapper.updateById(undo);

        List<Undo> undos = undoMapper.findByTaskId(undo.getTaskId());
        for(Undo u : undos){

            if(u.getFinished() != UndoFinishedFlagEnum.PROCESSEND.getValue()){

                Undo t = new Undo();

                t.setId(u.getId());
                t.setFinished(UndoFinishedFlagEnum.PROCESSEND.getValue());

                undoMapper.updateById(t);
            }
        }

        taskService.finished(targetUndo.getTaskId(), TaskStateFlagEnum.REJECT.getValue());
        procinstService.finished(targetUndo.getProcinstId(), ProcinstStateType.REJECT.getValue());

        //回调驳回处理业务
        ProcinstBO procinstBO = procinstService.get(targetUndo.getProcinstId());
        ProcdefBO procdefBO = procdefService.get(procinstBO.getProcdefId());
        TaskBO taskBO = taskService.get(targetUndo.getTaskId());
        WorkFlowListener workFlowListener = workFlowListenerMap.get("workFlowListener_" + procdefBO.getCode());
        if(workFlowListener == null){
            workFlowListener = workFlowListenerMap.get("defaultWorkFlowListener");
        }

        workFlowListener.reject(procinstBO, taskBO, get(param.getUndoId()));
    }

    @Override
    public List<UndoBO> listByTaskId(String taskId) {

        List<Undo> list = undoMapper.findByTaskId(taskId);

        return UndoConvert.INSTANCE.to(list);
    }

    @Override
    public List<UndoBO> listByProcinstId(String procinstId) {

        List<Undo> list = undoMapper.findByProcinst(procinstId);

        return UndoConvert.INSTANCE.to(list);
    }

    @Override
    public void finished(String id, Integer finished) {

        Undo undo = new Undo();

        undo.setId(id);
        undo.setFinished(finished);

        undoMapper.updateById(undo);

    }

}
